from datetime import datetime

import random
import re
from flask import abort, jsonify
from flask import current_app
from flask import make_response
from flask import request
from flask import session

from info import redis_store, constants, db
from info.models import User
from info.utils.captcha.captcha import captcha


from . import passport_blu
from ...utils.response_code import RET


@passport_blu.route('/logout')
def log_out():
    """退出登录
    1.用户点击退出,清除保存的session
    """
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    return jsonify(errno=RET.OK, errmsg='退出登录')


@passport_blu.route('/login', methods=['post'])
def log_in():
    """用户登录
    1.取出参数
    2.判断是否有值
    3.校验用户是否存在
    4.校验密码是否正确
    5.保持用户登录状态
    6.返回结果
    """
    data_dict = request.json
    mobile = data_dict.get('mobile')
    password = data_dict.get('password')
    # 判断是否有值
    if not all([mobile, password]):
        return jsonify(errno=RET.DATAERR, errmsg='参数错误')
    # 判断用户是否存在
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据查询错误')
    if not user:
        return jsonify(errno=RET.NODATA, errmsg='用户不存在')
    # 校验密码是否正确  (在models里定义的检查hash密码的函数  返回值为bool)
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg='用户名或密码错误')
    # 校验通过说明用户存在,保持用户的登录状态
    session['user_id'] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name
    # 记录用户最后一次登录的时间
    user.last_login = datetime.now()
    # 可以不用手动提交,使用SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    # try:
    #     db.session.commit()
    # except Exception as e:
    #     db.session.rollback(e)
    # 返回结果
    return jsonify(errno=RET.OK, errmsg='登录成功!')


@passport_blu.route('/register', methods=['post'])
def register():
    """注册账号
    1.获取手机号,短信验证码,密码
    2.判断是否有值
    3.判断手机号是否已经注册
    4.校验短信验证码
    5.创建一个user对象,添加到数据库
    6.记录用户的登录状态 session
    7.返回结果给前端z
    :return:
    """
    data_dict = request.json
    mobile = data_dict.get('mobile')
    sms_code = data_dict.get('smscode')
    password = data_dict.get('password')
    # 判断是否有数据
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')
    # 判断手机号是否已经被注册
    try:
        # 从数据库取数据
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据库查询错误')
    # 如果查到了数据 说明用户存在
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='用户已存在')
    # 从redis里取出真实的短信验证码
    try:
        real_sms_code = redis_store.get('sms_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='查询失败')
    # 判断验证码是否过期
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')
    # 校验验证码
    if sms_code != real_sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')
    # 代码执行到这里说明验证码校验通过,实例化一个user对象,并保存到数据库
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    # user.password调用了property,执行了加密功能,并把加密后的密码赋值给了password_hash
    user.password = password
    # 保存到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据保存失败')
    # 记录用户的登录状态(往session中保存数据)
    session['user_id'] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name
    # 记录用户最后一次登录的时间
    user.last_login = datetime.now()
    # try:
    #     db.session.commit()
    # except Exception as e:
    #     db.session.rollback(e)
    return jsonify(errno=RET.OK, errmsg='注册成功!')


@passport_blu.route('/sms_code', methods=['post'])
def get_sms_code():
    '''生成短信验证码
    1.取到前端发送过来的图片验证码内容 验证码id 手机号
    2.判断是否都有值
    3.判断手机号是否符合规则
    4.通过验证码id从redis里取出真实的验证码内容进行比较
    5.如果不一致,返回验证码错误
    6.如果一致,生成短信验证码的随机内容,发送给用户
    7.保存验证码内容到redis,以便用户在注册时验证
    '''
    # 取出参数
    data_dict = request.json
    mobile = data_dict.get("mobile")
    image_code_id = data_dict.get("image_code_id")
    image_code = data_dict.get("image_code")
    # 判断参数是否都存在
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')
    # 判断手机号是否符合规则
    if not re.match(r'1[345678]\d{9}', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号输入有误')
    # 取出真实的验证码内容
    try:
        real_image_code = redis_store.get('image_code_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='未找到数据')
    # 判断验证码是否过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')
    # 比较用户输入的验证码内容和数据库里的验证码内容
    if image_code.upper() != real_image_code.upper():
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')
    # 代码执行到这里说明验证码验证通过,,生成短信验证码随机内容并发送给用户
    sms_code = '%06d' % random.randint(0, 999999)
    current_app.logger.debug("短信验证码的内容：%s" % sms_code)
    # result = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], "1")
    # if result != 0:
    #     # 发送短信失败
    #     return jsonify(errno=RET.THIRDERR, errmsg="发送短信失败")
    # 保存短信验证码的内容
    try:
        redis_store.set('sms_' + mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.debug(e)
        # 保存短信验证码失败
        return jsonify(errno=RET.DBERR, errmsg="保存短信验证码失败")

        # 7. 返回发送成功的响应
    return jsonify(errno=RET.OK, errmsg="发送成功")


@passport_blu.route('/image_code')
def get_image_code():
    """生成图片验证码
    1.取到前端发过来的验证码
    2.判断参数是否有值
    3.生成图片验证码
    4.保存图片验证码的内容到redis
    5.返回图片给前端
    """
    # 取得图片验证码id,从url里取参数
    image_code_id = request.args.get('ImageCodeId', '')
    # 判断是否有值
    if not image_code_id:
        return abort(403)
    # 生成图片验证码 generate_captcha返回一个元祖对象
    name, text, image = captcha.generate_captcha()
    # 保存图片验证码到redis
    try:
        redis_store.set('image_code_' + image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return '666'
    # 返回图片给前端,设置ContentType=image/jpg
    response = make_response(image)
    response.headers['Content-Type'] = 'image/jpg'
    return response
